home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-01-12 | 14.7 KB | 568 lines | [TEXT/MPS ] |
- TITLE 'Pump driver'
- BLANKS ON
- CASE ON
- String Pascal
- Machine MC68020
-
- PRINT OFF
- INCLUDE 'Traps.a'
- INCLUDE 'ToolEqu.a'
- INCLUDE 'QuickEqu.a'
- INCLUDE 'SysEqu.a'
- INCLUDE 'SysErr.a'
- INCLUDE 'TimeEqu.a'
- INCLUDE 'Quickdraw.inc'
- INCLUDE 'GNEGlobals.inc'
- INCLUDE 'PumpErrs.inc'
- LOAD 'ProgStrucMacs.d'
- LOAD 'FlowCtlMacs.d'
- LOAD 'DRVRStruct.d'
- PRINT ON
-
- IMPORT HexSet,IntegerSet,AskFormat,RespondToRead
- IMPORT SerialComplete,TimeOutInstall
-
- ParamBlockSize equ 108
- ActionOffset equ csParam
- RequestOffset equ csParam+2
- InfoOffset equ csParam+4
- DCEPtr equ csParam+6
-
- IntegerFmt equ 0
- HexFmt equ 1
-
- Ask equ 0
- Set equ 1
-
- S_request equ 0
- R_request equ 1
- V_request equ 2
- I_request equ 3
-
- baud2400 equ 46
- stop10 equ 16384
- noParity equ 0
- data8 equ 3072
-
- EnabledFlags equ (1<<dStatEnable) + (1<<dCtlEnable) + (1<<dNeedTime)
- EventMask equ 1<<app1Evt ; Handle only driver events
-
- Owned equ %1100000000000000
-
- DrvrStorage EQU A3
- StringAddress EQU A1
-
- DStore Record 0
- WriteUnit DS.W 1
- ReadUnit DS.W 1
- TimeCount DS.L 1
- KillBlock DS.L 1
- KillTask DS.L 1
- IncomingLength DS.B 1
- IncomingString DS.B 9
- Align 2
- TableOffset equ *
- TableLen DS.W 1
- Table DS.W 5
- ENDR
-
- IOString Record 0
- OutgoingString DS.B 8
- ReadBuffer DS.B 1
- Align 2
- StringAllocation equ *
- ENDR
-
-
- EvRecord Record 0
- myEvent DS.L EventRecord ; Current event info
- ENDR
-
- DRVRStart DRVREntry
-
- DRVRBegin Save=A2-A4/D1-D2,with=(DStore,IOString,GNEGlobals,EvRecord);
-
- DC.B EnabledFlags
- DC.B 0 ; Lower byte is unused
- DC.W 7*60 ; periodic actions every 7 seconds
- DC.W EventMask
- DC.W 0 ; No menu for this accessory
-
- ; org drvrOpen
-
- DC.W DRVROpen ; Open routine
- DC.W DRVRPrime ; Prime
- DC.W DRVRControl ; Control
- DC.W DRVRStatus ; Status
- DC.W DRVRClose ; Close
-
- DRVRTitle
- DC.B 'PumpDriver' ; Driver Name
- ALIGN 2 ; Word align
-
-
- DRVROpen DRVREnter
-
- MOVE.L A1,A2
-
- * Load the pump request table from the resource fork
-
- ResHandle equ A4
-
- Call _GetNamedResource:L ( #'PDDF':L , #'Table':A ),ResHandle:L
- EXG A0,ResHandle
- _HLock
- _GetHandleSize
- If# D0 LT.L #0 Then.S
- MOVE.W #openErr,ioResult(ResHandle)
- Return
- EndIf#
- EXG A0,ResHandle
- MOVE.L D0,D1
-
- MOVE.L A0,-(SP)
-
- * Get a new handle to put the Driver globals and the pump request table into
-
- MOVE.L A1,-(SP)
- ADD.L #TableOffset,D0
- _NewHandle ,clear
- _HLock
- MOVE.L A0,dCtlStorage(A2)
- MOVE.L (A0),A1
- MOVE.L A1,DrvrStorage
- ADD.L #TableOffset,A1
- MOVE.L (ResHandle),A0
- MOVE.L D1,D0
- _BlockMove
- Call _ReleaseResource ( ResHandle:L )
- MOVE.L (SP)+,A1
-
- * Open the serial drivers and set them up for the pump
-
- MOVE.L #ParamBlockSize,D0
- _NewPtr ,clear
- LEA #'.AOUT',A2
- MOVE.L A2,ioNamePtr(A0)
- MOVE.B #fsWrPerm,ioPermssn(A0)
- _Open
-
- If# D0 NE.W #noErr Then.S
- MOVE.L (SP)+,A0
- MOVE.W #openErr,ioResult(A0)
- Return
- EndIf#
-
- MOVE.W ioRefNum(A0),WriteUnit(DrvrStorage)
-
- * Set the output port for 2400 baud, 1 stop, no parity, eight bit communication
-
- PortSetting equ baud2400+stop10+noParity+data8
-
- MOVE.W #PortSetting,csParam(A0)
- MOVE.W #8,csCode(A0)
- _Control
-
- * Open the input port
-
- LEA #'.AIN',A2
- MOVE.L A2,ioNamePtr(A0)
- MOVE.B #fsRdPerm,ioPermssn(A0)
- _Open
-
- If# D0 NE.W #noErr Then.S
- MOVE.L (SP)+,A0
- MOVE.W #openErr,ioResult(A0)
- Return
- EndIf#
-
- MOVE.W ioRefNum(A0),ReadUnit(DrvrStorage)
-
- * Set the input port for 2400 baud, 1 stop, no parity, eight bit communication
-
- MOVE.W #PortSetting,csParam(A0)
- MOVE.W #8,csCode(A0)
- _Control
- _KillIO
- _DisposPtr
-
- * Set up a parameter block for the serial IO timeout function. The pointer is stored in the
- * Driver private storage. Also insert a task into the time manager queue which performs the
- * IO timeout function.
-
- MOVE.L #ParamBlockSize,D0
- _NewPtr ,clear
- MOVE.L A0,KillBlock(DrvrStorage)
- MOVE.L #1500,TimeCount(DrvrStorage)
- MOVE.L #tmQSize,D0
- _NewPtr
- MOVE.L A0,KillTask(DrvrStorage)
- Call TimeOutInstall ( A0:L , KillBlock(DrvrStorage):L )
-
- * Add a routine to the GNEFilter chain to handle calling the pump driver with appropriate
- * driver events. The filter rouitne is stored in a resource of type 'GNEF',
- * named 'GNEFilter', and is accessed by name so that multiple drivers can
- * use the same filter. The resource must be locked & nonpurgeable, but should
- * not be preloaded. The driver gets a handle to the resource, dereferences
- * it, and checks the Drvr_num field. If the value there is zero, then we
- * store the value in the system global JGNEFilter in the longword above
- * the entry point for our GNE filter, and place the GNE filter pointer in
- * JGNEFilter. The address of our GNE filter is found by adding the offset
- * found in the first word of the resource to the dereferenced handle. We
- * also allocate a pointer for the filter's use and store it at the offset
- * Control_Ptr. Whether or not the value of Drvr_num was zero, we then check
- * to make sure the driver reference number is not already in the list, and if
- * not, increment Drvr_num and add the driver's reference number to the list
- * of cooperating drivers.
-
- Call _GetNamedResource:L ( #'GNEF':L , #'GNEFilter':A ),A2
- CMPA #0,A2
- If# NE Then.S
- MOVE.L (A2),A2
- MOVE.W Drvr_num(A2),D1
- If# D1 EQ.W #0 Then.S
- MOVE.W (A2),D0
- LEA (A2,D0.W),A3
- MOVE.L JGNEFilter,-4(A3)
- MOVE.L A3,JGNEFilter
- MOVE.L #ParamBlockSize,D0
- _NewPtr ,clear
- MOVE.L A0,Control_Ptr(A2)
- EndIf#
- MOVE.W dCtlRefNum(A1),D2
- If# D1 LE #entry_slots Then.S
- For# D1 DownTo #1 Do.S
- If# Drvr_num(A2,D1.W*2) EQ.W D2 Then.S
- GoTo#.S DuplicateDrvr
- EndIf#
- EndF#
-
- ADD.W #1,Drvr_num(A2)
- MOVE.W Drvr_num(A2),D1
- MOVE.W D2,Drvr_num(A2,D1.W*2)
- Else#.S
-
- * Get the Resource ID for the driver to calculate the ID of owned Alert (sub ID 0)
-
- LEA DRVREntry,A0
- _RecoverHandle
- LINK A6,#-12
- Call _GetResInfo ( A0:L , (A6):A , 4(A6):A , 8(A6):L )
- MOVE.W (A6),D2
- UNLK A6
- MULU #32,D2
- ADD.W #Owned,D2
- Call _CautionAlert:W ( D2:W , 0:L ),CC
- EndIf#
- EndIf#
- DuplicateDrvr:
- MOVE.L (SP)+,A0
- MOVE.W #openErr,ioResult(A0)
- Return
-
- DRVRClose DRVREnter
-
- MOVE.L A0,-(SP)
- MOVE.L dCtlStorage(A1),A2
- MOVE.L (A2),DrvrStorage
-
- MOVE.L #ParamBlockSize,D0
- _NewPtr ,clear
- MOVE.W ReadUnit(DrvrStorage),ioRefNum(A0)
- _Close
- MOVE.W WriteUnit(DrvrStorage),ioRefNum(A0)
- _Close
- _DisposPtr
-
- MOVE.L KillTask(DrvrStorage),A0
- _RmvTime
- _DisposPtr
- MOVE.L KillBlock(DrvrStorage),A0
- _DisposPtr
-
- Move.L A2,A0
- _DisposHandle
-
- MOVE.W dCtlRefNum(A1),D2
- Call _GetNamedResource:L ( #'GNEF':L , #'GNEFilter':A ),A2
- CMPA #0,A2
- If# NE Then.S
- MOVE.L (A2),A3
- MOVE.W Drvr_num(A3),D1
- If# D1 GT.W #1 Then.S
- While# D2 NE.W Drvr_num(A3,D1.W*2) Do.S
- DBEQ.W D1,DuplicateClose
- EndW#
- If# D1 NE.W Drvr_num(A3) Then.S
- ADD.W #1,D1
- For# D1 To Drvr_num(A3) Do.S
- LEA Drvr_num(A3,D1.W*2),A4
- MOVE.W (A4),-2(A4)
- EndF#
- EndIf#
- SUBQ.W #1,Drvr_num(A3)
-
- ElseIf#.S D1 EQ.W #1 Then.S
- If# D2 NE.W Drvrentries(A3) Then.S
- GoTo#.S DuplicateClose
- EndIf#
- MOVE.L GNE_Next(A3),JGNEFilter
- Call _ReleaseResource ( A2:L )
- EndIf#
- EndIf#
- DuplicateClose:
- MOVE.W #noErr,D0
- MOVE.L (SP)+,A0
-
- DRVRExit ioTrap(A0)
-
- DRVRPrime DRVREnter
-
- MOVE.W noErr,D0
- Return
-
-
- DRVRStatus DRVREnter
-
- * First, check to see if this is an immediate call. If so, it "jumps the line", and will be the
- * next call serviced after the current one (if any) is completed.
-
- MOVE.W ioTrap(A0),D1
- BTST #noQueueBit,D1
- If# NE Then.S ;An Immediate call
- LEA dCtlQHead(A1),A2
- CMP.L #0,(A2)
- If# EQ Then.S ;The queue is empty
- _Status ,async
- Return
- EndIf#
-
- MOVE.L (A2),D1
- CMP.L 4(A2),D1
- If# EQ Then.S ;The queue has only one entry
- _Status ,async
- Return
- EndIf#
-
- MOVE.W ioTrap(A0),D1
- BCLR #noQueueBit,D1 ;Fool the driver into thinking this
- BSET #asyncTrpBit,D1 ;is an asynchronous queue entry
- MOVE.W D1,ioTrap(A0)
- MOVE.W #1,ioResult(A0)
-
- MOVE.L (A2),A2 ;Get parameter block of queue head
- MOVE.L (A2),(A0) ;Put qLink of qHead in current parameter block
- MOVE.L A0,(A2) ;and replace it with current parameter block pointer
- Return
- EndIf#
-
- MOVE.L A0,A2
- MOVE.L dCtlStorage(A1),A4
- MOVE.L (A4),A4
- MOVE.L A1,DCEPtr(A2)
-
- MOVE.W TableLen(A4),D1
- MOVE.W RequestOffset(A2),D0
- If# D0 GT.W D1 Then.S ;Not a valid pump call
- MOVE.W #statusErr,ioResult(A2)
- MOVE.L A2,D0
- MOVE.W #app2Evt,A0
- _PostEvent
- MOVE.L A2,A0
- MOVE.L #statusErr,D0
- DRVRExit ioTrap(A0)
- EndIf#
-
- * Get some storage for the string we will build
-
- MOVE.L #StringAllocation,D0
- _NewPtr ,clear
- MOVE.L A0,A3
-
- * Get some storage for the parameter block that is used for serial driver calls
-
- MOVE.L #ParamBlockSize,D0
- _NewPtr ,clear
- MOVE.L A3,ioBuffer(A0)
- MOVE.L A2,ioMisc(A0)
-
-
- * Now, get the string formatting info out of the Driver private storage
-
- MOVE.W WriteUnit(A4),ioRefNum(A0)
- MOVE.W RequestOffset(A2),D0
- ADD.W D0,D0
- Add.W #TableOffset+2,D0
- MOVE.L A0,-(SP)
-
- If# ActionOffset(A2) EQ.W #Ask Then.S
- Call AskFormat ( A3:L , ioReqCount(A0):A , (A4,D0.W):B )
- ElseIf#.S 1(A4,D0.W) EQ.B #IntegerFmt Then.S
- Call IntegerSet ( A3:L , ioReqCount(A0):A , (A4,D0.W):B ,\
- InfoOffset(A2):W )
- Else#.S
- Call HexSet ( A3:L , ioReqCount(A0):A , (A4,D0.W):B ,\
- InfoOffset(A2):W )
- EndIf#
-
- MOVE.L (SP)+,A0
- LEA SerialComplete,A3
- MOVE.L A3,ioCompletion(A0)
- _Write ,async
-
- * Set up the time manager task to KillIO on the channel in TimeCount milliseconds. KillBlock
- * is a previously allocated parameter block, which is passed to TimeOutInstall and stored
- * locally (that is, in-line in the code). This is necessary because the routine executes at
- * interrupt level, and is part of a driver, and thus cannot use the memory manager or application
- * globals.
-
- MOVE.L KillBlock(A4),A0
- MOVE.L WriteUnit(A4),ioRefNum(A0)
- MOVE.L KillTask(A4),A0
- MOVE.L TimeCount(A4),D0
- _PrimeTime
-
- MOVE.L #noErr,D0
- Return
-
- DRVRControl DRVREnter
-
- If# csCode(A0) EQ.W #accEvent Then
- MOVE.L csParam(A0),A2
- MOVE.L myEvent.message(A2),A2
- MOVE.W ioTrap(A2),D2
- AND.W #$00FF,D2
- MOVE.W ioResult(A2),D3
-
- * Check to see the serial call was not aborted by KillIO. If so, inform the application,
- * dequeue the pump driver call, and return
-
- If# D3 EQ.W #abortErr Then.S
- MOVE.L ioMisc(A2),A0
- EXG A0,A2
- _DisposPtr
- MOVE.W #TimeOut,ioResult(A2)
- ADD.W D2,ioResult(A2)
- MOVE.L A2,D0
- MOVE.W #app2Evt,A0
- _PostEvent
- MOVE.L #TimeOut,D0
- MOVE.L A2,A0
- DRVRExit ioTrap(A0)
- EndIf#
-
- * The serial call did not time out, so figure out if it was a READ or a WRITE by examining
- * the low nybble of the trap field of the parameter block.
-
- If# D2 EQ.W #aRdCmd Then
-
- * READ - examine the character read. If it is a '*', the new pump is just wasting our valuable
- * time, and so we ignore it and queue another read. If it is a carraige return, we call
- * RespondToRead to interpret the completed pump response. Any other character is
- * incorporated into the string being built at IncomingString and increment the
- * IncomingLength byte, and another READ is queued. If the byte exceeds 8 characters, we
- * have a problem.
-
- MOVE.L ioBuffer(A2),A3
- MOVE.B (A3),D1
- MOVE.L dCtlStorage(A1),A4
- MOVE.L (A4),A4
- If# D1 EQ.B #13 Then.S
- MOVE.L KillTask(A4),A0
- CLR.L tmCount(A0)
- MOVE.L ioMisc(A2),A3
- Call RespondToRead
- MOVE.L ioMisc(A2),A0
- EXG A0,A2
- _DisposPtr
- MOVE.L A2,D0
- MOVE.W #app2Evt,A0
- _PostEvent
- CLR.B IncomingLength(A4)
- CLR.L IncomingString(A4)
- CLR.L IncomingString+4(A4)
- CLR.L D0
- MOVE.L A2,A0
- DRVRExit ioTrap(A0)
- ElseIf#.S D1 EQ.B #'*' Then.S
- MOVE.L A2,A0
- _Read ,async
- Return
- Else#.S
- MOVE.B IncomingLength(A4),D0
- EXT.W D0
- MOVE.B D1,IncomingString(A4,D0.W)
- ADD.W #1,D0
- If# D0 LE.W #8 Then.S
- MOVE.B D0,IncomingLength(A4)
- Else#.S
- MOVE.L KillBlock,A0
- MOVE.W ReadUnit(A4),ioRefNum(A0)
- _KillIO
- MOVE.L ioMisc(A2),A0
- EXG A0,A2
- _DisposPtr
- MOVE.W #TooManyCharacters,ioResult(A2)
- MOVE.L A2,D0
- MOVE.W #app2Evt,A0
- _PostEvent
- MOVE.L A2,A0
- MOVE.L #TooManyCharacters,D0
- DRVRExit ioTrap(A0)
-
- EndIf#
- MOVE.L A2,A0
- _Read ,async
- Return
- EndIf#
- ElseIf#.S D2 EQ.W #aWrCmd Then.S
- MOVE.L dCtlStorage(A1),A4
- MOVE.L (A4),A4
- MOVE.L KillBlock(A4),A0
- MOVE.W ReadUnit(A4),ioRefNum(A0)
- MOVE.L A2,A0
- MOVE.W ReadUnit(A4),ioRefNum(A0)
- MOVE.L #1,ioReqCount(A0)
- MOVE.L ioBuffer(A0),A2
- LEA ReadBuffer(A2),A2
- MOVE.L A2,ioBuffer(A0)
- LEA SerialComplete,A4
- MOVE.L A4,ioCompletion(A0)
- _Read ,async
- Return
- EndIf#
- ElseIf#.S csCode(A0) EQ.W #accRun Then.S
- MOVE.L A0,-(SP)
- MOVE.L #ParamBlockSize,D0
- _NewPtr ,clear
- MOVE.W dCtlRefNum(A1),ioRefNum(A0)
- MOVE.W #S_request,RequestOffset(A0)
- MOVE.W #Ask,ActionOffset(A0)
- CLR.L ioCompletion(A0)
- _Status ,async
- MOVE.L (SP)+,A0
-
- ElseIf#.S csCode(A0) EQ.W #killCode Then.S
-
- MOVE.L #ParamBlockSize,D0
- MOVE.L dCtlStorage(A1),A2
- MOVE.L (A2),A2
- _NewPtr ,clear
- MOVE.W ReadUnit(A2),ioRefNum(A0)
- _KillIO
- MOVE.W WriteUnit(A2),ioRefNum(A0)
- _KillIO
- _DisposPtr
- Return
-
- ElseIf#.S csCode(A0) EQ.W #goodBye Then.S
- JMP DRVRClose
- EndIf#
-
- MOVE.L #noErr,D0
- DRVRExit ioTrap(A0)
-
- ENDP
-
- END
-